package com.yxw.yx_hotel.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxw.yx_hotel.dto.UserLoginDTO;
import com.yxw.yx_hotel.dto.UserPhoneLoginDTO;
import com.yxw.yx_hotel.dto.UserSendCodeDTO;
import com.yxw.yx_hotel.entity.YxSmsTemplateEntity;
import com.yxw.yx_hotel.entity.YxSysUserEntity;
import com.yxw.yx_hotel.mapper.SmsTemplateMapper;
import com.yxw.yx_hotel.mapper.UserMapper;
import com.yxw.yx_hotel.service.LoginService;
import com.yxw.yx_hotel.utils.HuaWeiSmsUtil;
import com.yxw.yx_hotel.utils.JwtUtil;
import com.yxw.yx_hotel.utils.RedisManager;
import com.yxw.yx_hotel.utils.UserUtil;
import com.yxw.yx_hotel.vo.LoginUserVo;
import com.yxw.yx_hotel.vo.UserInfoVo;
import com.yxw.yx_hotel.vo.UserTokenVo;
import com.yxw.yxnet_cd_center.common.constant.CommonConstant;
import com.yxw.yxnet_cd_center.common.constant.RedisIdConstant;
import com.yxw.yxnet_cd_center.common.dto.BaseDTO;
import com.yxw.yxnet_cd_center.common.dto.HuaWeiSmsDTO;
import com.yxw.yxnet_cd_center.common.enums.CommonErrorEnum;
import com.yxw.yxnet_cd_center.common.enums.NoticeTypeEnum;
import com.yxw.yxnet_cd_center.common.exception.BaseException;
import com.yxw.yxnet_cd_center.common.utils.PasswordUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

/**
 * 登录管理
 *
 * @author liuxin
 * @date 2023.09.12
 */
@Service
public class LoginServiceImpl extends ServiceImpl<UserMapper, YxSysUserEntity> implements LoginService {


    @Resource
    private RedisManager redisManager;

    @Autowired
    private UserUtil userUtil;

    @Resource
    private HuaWeiSmsUtil smsComponent;

    @Autowired
    private SmsTemplateMapper smsTemplateMapper;

    /**
     * 登出
     *
     * @param baseDTO
     */
    @Override
    public void logout(BaseDTO baseDTO) {
        UserTokenVo userTokenVo = (UserTokenVo) redisManager.get(RedisIdConstant.LOGIN_TOKEN + userUtil.getLoginUserId());
        if (userTokenVo != null) {
            redisManager.del(RedisIdConstant.LOGIN_TOKEN + userUtil.getLoginUserId());
        }
        //修改登陆状态
        YxSysUserEntity user = baseMapper.selectById(userUtil.getLoginUserId());
        if (null != user) {
            user.setLastLoginTime(user.getLoginTime());
            user.setLoginTime(null);
            baseMapper.updateById(user);
        }
    }

    /**
     * 账号密码登录
     *
     * @param userLoginDTO
     * @return
     */
    @Override
    public LoginUserVo login(UserLoginDTO userLoginDTO) {
        // 查询用户信息
        YxSysUserEntity user = baseMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getUserNum, userLoginDTO.getUserNum())
                .eq(YxSysUserEntity::getUserStatus, 1));

        // 如果用户不存在
        if (user == null) {
            throw new BaseException("账号或密码不正确");
        }

        // 查询登录失败次数
        Object obj = redisManager.get(RedisIdConstant.LOGIN_FAIL_COUNT + user.getUserId());
        int cnt = (obj != null) ? (int) obj : 0;

        // 如果失败次数达到五次，则提示
        if (cnt >= 5) {
            throw new BaseException("账号密码登录次数超限，请用手机号登录");
        }

        // 校验账号密码是否正确
        String password = PasswordUtil.signUserPassword(user.getUserId(), userLoginDTO.getPassword());
        if (!Objects.equals(password, user.getPassword())) {
            // 账号密码错误，失败次数+1
            redisManager.set(RedisIdConstant.LOGIN_FAIL_COUNT + user.getUserId(), cnt + 1);
            throw new BaseException("账号或密码不正确");
        }

        // 登录成功，清空登录失败次数
        redisManager.set(RedisIdConstant.LOGIN_FAIL_COUNT + user.getUserId(), 0);

        LoginUserVo loginUserVo = getLoginUserVo(user);
        user.setLoginTime(new Date());
        baseMapper.updateById(user);
        return loginUserVo;
    }

    @Override
    public LoginUserVo phone(UserPhoneLoginDTO userPhoneLoginDTO) {
        YxSysUserEntity user = baseMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getMobilePhone, userPhoneLoginDTO.getMobilePhone())
                .eq(YxSysUserEntity::getUserStatus, 0)
        );
        if (user == null) {
            throw new BaseException("账号不存在");
        }
        String code = (String) redisManager.get(RedisIdConstant.LOGIN_SMS_CODE + userPhoneLoginDTO.getMobilePhone());
        if (!userPhoneLoginDTO.getCode().equals(code)) {
            throw new BaseException(CommonErrorEnum.SMS_VERIFICATION_CODE);
        }

        // 登录成功，清空登录失败次数
        redisManager.set(RedisIdConstant.LOGIN_FAIL_COUNT + user.getUserId(), 0);

//        //发送异地登录提醒,下线已登录账号
//        this.sendOfflineNotice(user);
        LoginUserVo loginUserVo = getLoginUserVo(user);
        user.setLoginTime(new Date());
        baseMapper.updateById(user);
        return loginUserVo;
    }

    /**
     * 发送验证
     *
     * @param userSendCodeDTO
     */
    @Override
    public void send(UserSendCodeDTO userSendCodeDTO) {
        String code = RandomUtil.randomNumbers(6);
        redisManager.set(RedisIdConstant.LOGIN_SMS_CODE + userSendCodeDTO.getPhone(), code, 5 * 60);
        //查询模板配置
        LambdaQueryWrapper<YxSmsTemplateEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YxSmsTemplateEntity::getTemplateCode, NoticeTypeEnum.SMS_CODE.getTemplateCode());
        YxSmsTemplateEntity entity = smsTemplateMapper.selectOne(wrapper);
        if (null == entity) {
            throw new BaseException("短信模板未配置");
        }
        HuaWeiSmsDTO dto = new HuaWeiSmsDTO();
        dto.setTemplateParas("[\"" + code + "\"]");
        dto.setPhone(userSendCodeDTO.getPhone());
        dto.setSender(entity.getSender());
        dto.setTemplateId(entity.getHwTemplateId());
        smsComponent.sendSmsCode(dto);
    }

    /**
     * 刷新token接口
     *
     * @param request
     * @return
     */
    @Override
    public LoginUserVo refreshToken(HttpServletRequest request) {
        //获取请求头token信息
        Cookie[] cookies = request.getCookies();
        if (null == cookies || cookies.length == 0) {
            throw new BaseException(CommonErrorEnum.REQUEST_HEADER_GET_TOKEN_EXCEPTION);
        }
        String token = "";
        for (Cookie cookie : cookies) {
            if (CommonConstant.TOKEN.equals(cookie.getName())) {
                token = cookie.getValue();
            }
        }
        if (StringUtils.isBlank(token)) {
            throw new BaseException(CommonErrorEnum.REQUEST_HEADER_GET_TOKEN_EXCEPTION);
        }
        //解析token
        //TokenInfo tokenInfo = TokenUtil.getTokenInfoByToken(token);
        //Long userId = tokenInfo.getUserId();
        Long userId = JwtUtil.getUserIdFromToken(token);
        if (null == userId) {
            throw new BaseException("token字符中不包含userId");
        }
        YxSysUserEntity user = baseMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getUserId, userId)
                .eq(YxSysUserEntity::getUserStatus, 0)
        );
        if (null == user) {
            throw new BaseException(CommonErrorEnum.VERIFY_USER_TOKEN_EXCEPTION);
        }
        return getLoginUserVo(user);
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------------
    private LoginUserVo getLoginUserVo(YxSysUserEntity user) {
        LoginUserVo loginUserVo = new LoginUserVo();
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtil.copyProperties(user, userInfoVo);
        long checkCode = System.currentTimeMillis();
        UserTokenVo userTokenVo = new UserTokenVo();
        BeanUtil.copyProperties(user, userTokenVo);
        userTokenVo.setCheckCode(checkCode);
        userTokenVo.setExpirationDate(LocalDateTime.now().plusMinutes(30));
        String token = JwtUtil.generateToken(userTokenVo, checkCode);
        loginUserVo.setUser(userInfoVo);
        loginUserVo.setToken(token);
        UserTokenVo tokenVo = (UserTokenVo) redisManager.get(RedisIdConstant.LOGIN_TOKEN + user.getUserId());
        if (tokenVo != null) {
            redisManager.del(RedisIdConstant.LOGIN_TOKEN + user.getUserId());
        }
        redisManager.set(RedisIdConstant.LOGIN_TOKEN + user.getUserId(), userTokenVo, 60 * 60);
        return loginUserVo;
    }

    /**
     * 发送用户下线通知
     */
//    private void sendOfflineNotice(YxCsUserEntity user) {
//        MqttInforSystemVO systemVO = new MqttInforSystemVO();
//        systemVO.setContent("该账号在别的地方登录,如非本人操作,请尽快修改登录密码");
//        systemVO.setMsgType("sys");
//        systemVO.setContentType("offline");
//        systemVO.setRecv(String.valueOf(user.getId()));
//        //下线操作
//        systemVO.setNotificationType("offline");
//        mqttGateway.sendToMqtt(MqttTopicEnum.SYSTEM_OFFLINE_TOPIC.getTopic() + user.getId(), JsonUtils.toJson(systemVO));
//    }
}
